/**
 * 
 */
package it.uniroma3.dia.digraph.algorithm;

import it.uniroma3.dia.digraph.algorithm.utility.Utility;
import it.uniroma3.dia.digraph.view.View;

import java.util.InputMismatchException;
import java.util.List;
import java.util.Map;

import org.graphdrawing.graphml.xmlns.EdgeType;
import org.graphdrawing.graphml.xmlns.GraphType;
import org.graphdrawing.graphml.xmlns.NodeType;

/**
 * Models an algorithm to be applied on some graph
 * @author BarycentricCoords
 *
 */
public abstract class Algorithm {
	
	protected View view;
	protected GraphType graph;
	protected Map<String, NodeType> idToNodes;
	protected List<EdgeType> edgeList;
	
	
	
	/**
	 * Runs the algoritm on the specified input
	 * @param inputGraphs
	 */
	public void run(GraphType...inputGraphs){
		this.checkInput(inputGraphs);
		this.standardInit(inputGraphs);
		this.view.pack();
		this.view.setVisible(true);
		this.view.repaint();
		this.apply(inputGraphs);
	}
	
	
	/**
	 * Checks input correctness
	 * @param inputGraphs the input
	 * @throws InputMismatchException if input is not correct
	 */
	public abstract void checkInput(GraphType[] inputGraphs) throws InputMismatchException;

	/**
	 * Initialises fields
	 */
	protected abstract void init(GraphType...inputGraphs);
	
	/**
	 * @return the idToNodes
	 */
	public Map<String, NodeType> getIdToNodes() {
		return idToNodes;
	}



	/**
	 * @param idToNodes the idToNodes to set
	 */
	public void setIdToNodes(Map<String, NodeType> idToNodes) {
		this.idToNodes = idToNodes;
	}



	/**
	 * @return the edgeList
	 */
	public List<EdgeType> getEdgeList() {
		return edgeList;
	}



	/**
	 * @param edgeList the edgeList to set
	 */
	public void setEdgeList(List<EdgeType> edgeList) {
		this.edgeList = edgeList;
	}



	/**
	 * Runs the algorithm on the given input graph
	 * @param inputGraphs the input graphs
	 */
	public abstract void apply(GraphType... inputGraphs);
	
	
	
	/**
	 * Updates the view to display the new configuration of the graph
	 */
	public void updateView(){
		this.view.update(graph);
		this.view.repaint();
	}
	
	/**
	 * @return the view
	 */
	public View getView() {
		return view;
	}


	/**
	 * @param view the view to set
	 */
	public void setView(View view) {
		this.view = view;
	}


	/**
	 * @return the graph
	 */
	public GraphType getGraph() {
		return graph;
	}


	/**
	 * @param graph the graph to set
	 */
	public void setGraph(GraphType graph) {
		this.graph = graph;
	}


	public void standardInit(GraphType...inputGraphs) {
		//standard init
		this.graph = inputGraphs[0];
		this.edgeList = this.graph.getEdgeCollection().getEdge();
		this.idToNodes = Utility.extractNodes(this.graph);
		this.view = new View(this.graph);
		this.view.pack();
		this.view.setVisible(true);
		this.updateView();
		this.init(inputGraphs);
		
	}
}
